import { App } from "../../application";
import GeoUtils from "../../utils/GeoUtils";
import Helper from "../../utils/Helper";
import { BaseTileMap } from "../../map/BaseTileMap";
import { TileSwitcher } from "./TileSwitcher";
import TaskManager from "../../utils/TaskManager";
import Config from "../../application/constants/Config";

class TileSwitchController {
    private baseTileMap: BaseTileMap;
    private switcherLru: Array<TileSwitcher>;
    private tileTaskMap: Map<string, TileSwitcher>; //一次层级切换时，要执行瓦片加载任务的瓦片编号。新的瓦片加载成功后，该set中的编号要删除
    private eyeCol;
    private eyeRow;
    private eyeZoom;
    private taskManger;

    public constructor(baseTileMap: BaseTileMap) {
        this.baseTileMap = baseTileMap;
        this.tileTaskMap = new Map<string, TileSwitcher>();
        this.switcherLru = new Array<TileSwitcher>();
        this.taskManger = new TaskManager({ excuteByBatch: true });
    }

    private comapre(curTile, otherTile) {
        if (!curTile['options'] || !otherTile['options']) {
            return 0;
        }
        let lrcA = curTile['options'].lrc;
        let lrcB = otherTile['options'].lrc;
        // let distance = Math.sqrt( (lrc.x - this.eyeCol)*(lrc.x - this.eyeCol) + (lrc.y - this.eyeRow)*(lrc.y - this.eyeRow) 
        //     + (lrc.z - this.eyeZoom)*(lrc.z - this.eyeZoom) );

        let distanceA = ((lrcA.x - this.eyeCol) * (lrcA.x - this.eyeCol) + (lrcA.y - this.eyeRow) * (lrcA.y - this.eyeRow) + (lrcA.z - this.eyeZoom) * (lrcA.z - this.eyeZoom));
        let distanceB = ((lrcB.x - this.eyeCol) * (lrcB.x - this.eyeCol) + (lrcB.y - this.eyeRow) * (lrcB.y - this.eyeRow) + (lrcB.z - this.eyeZoom) * (lrcB.z - this.eyeZoom));
        return distanceA - distanceB;
    }

    public switch(isDown: boolean, tileRange: { minCol: number, maxCol: number, minRow: number, maxRow: number, zoom: number }) {
        this.tileTaskMap.clear();

        // if (this.switcherLru.length >= this.maxLruSize) {
            let removeCount = this.switcherLru.length;// - this.maxLruSize;
        // }

        let self = this;
        let tileList = new Array<string>();
        let removeArray = [];

        let cameraPositon = App.getInstance().three.camera.position;
        this.eyeCol = GeoUtils.getC10(cameraPositon.x, tileRange.zoom);
        this.eyeRow = GeoUtils.getR10(cameraPositon.y, tileRange.zoom);
        this.eyeZoom = tileRange.zoom;

        this.baseTileMap.children.sort(this.comapre.bind(this));
        let switcherList = new Array<TileSwitcher>();

        this.taskManger.abort();
        this.taskManger = new TaskManager({ excuteByBatch: true });
        let priorityValue = 0;
        let tempIndex = 0;
        let mapLayCount = App.getInstance().map.availableBaseMapNum;
        let maxLoadCount = Math.max(Math.ceil(Config.Map.patchLoadCount / mapLayCount), 1);
        if (!isDown) { //地图向上缩放
            this.baseTileMap.children.forEach(oldTile => {
                if (!oldTile['options']) {
                    return;
                }

                tempIndex++;
                if(tempIndex % maxLoadCount == 0){
                    priorityValue++;
                }
                let lrc = oldTile['options'].lrc;
                let task = {
                    //通过优先级参数实现的节流机制 缓存瓦片5个为一批次，全部加载完成后再进行下一次批处理
                    //priority为任务优先级，这个值越小，任务优先级越高，最小为0。若TaskManager设置为根据批次执行，则会根据优先级分组
                    // priority: Config.Map.maxZoom - lrc.z,
                    priority: priorityValue,
                    //异步任务必须将这个值设置为true
                    asyn: true,
                    //complete属性原则上来讲不需要设置，但task没有写成类，为了保证编译通过，所以设置为空函数，在taskmananger内部，会对complete重写
                    complete: function () { },
                    //excute为任务执行时的具体操作
                    excute: function () {
                        // let lrc = oldTile['options'].lrc;
                        let parentLrc = { x: Math.floor(lrc.x / 2), y: Math.floor(lrc.y / 2), z: lrc.z - 1 };
                        let parentLrcStr = JSON.stringify(parentLrc);

                        if (!self.tileTaskMap.has(parentLrcStr)) {
                            let newTileNumList = [];
                            newTileNumList.push(parentLrc);
                            let tileSwitcher = new TileSwitcher(self.baseTileMap, oldTile, newTileNumList, tileRange);
                            let isSwitch = tileSwitcher.switch(tileList); //判断newTileNumList中的瓦片是否在当前地图层级，并且是否在当前地图加载范围内
                            if (!isSwitch) {
                                removeArray.push(oldTile);
                            } else {
                                self.tileTaskMap.set(parentLrcStr, tileSwitcher);
                                switcherList.push(tileSwitcher);

                                self.switcherLru.push(tileSwitcher);
                            }
                        } else {
                            let tileSwitcher = self.tileTaskMap.get(parentLrcStr);
                            if (tileSwitcher.isCanSwitch()) {
                                tileSwitcher.addExtraOldTile(oldTile);
                            }
                        }

                        task.complete();
                    },
                }
              this.taskManger.add(task);


            });

            if (this.baseTileMap.tileType == 'shape') { //shape数据图层，如果超出图层限制，就在这里删除掉removeArray数组中的元素
                removeArray.forEach(element => {
                    element.dispose();
                });
            }
        } else { //地图向下缩放
            this.baseTileMap.children.forEach(oldTile => {
                if (!oldTile['options']) {
                    return;
                }

                tempIndex++;
                if(tempIndex % maxLoadCount == 0){
                    priorityValue++;
                }
                let lrc = oldTile['options'].lrc;
                let task = {
                    //通过优先级参数实现的节流机制 缓存瓦片5个为一批次，全部加载完成后再进行下一次批处理
                    //priority为任务优先级，这个值越小，任务优先级越高，最小为0。若TaskManager设置为根据批次执行，则会根据优先级分组
                    // priority: Config.Map.maxZoom - lrc.z,
                    priority: priorityValue,
                    //异步任务必须将这个值设置为true
                    asyn: true,
                    //complete属性原则上来讲不需要设置，但task没有写成类，为了保证编译通过，所以设置为空函数，在taskmananger内部，会对complete重写
                    complete: function () { },
                    //excute为任务执行时的具体操作
                    excute: function () {
                        // let lrc = oldTile['options'].lrc;
                        let parentLrcStr = JSON.stringify(lrc);

                        let leftTopChildLrc = { x: lrc.x * 2, y: lrc.y * 2, z: lrc.z + 1 };
                        let leftBottomChildLrc = { x: lrc.x * 2, y: lrc.y * 2 + 1, z: lrc.z + 1 };
                        let rightTopChildLrc = { x: lrc.x * 2 + 1, y: lrc.y * 2, z: lrc.z + 1 };
                        let rightBottmChildLrc = { x: lrc.x * 2 + 1, y: lrc.y * 2 + 1, z: lrc.z + 1 };

                        let newTileNumList = [];
                        newTileNumList.push(leftTopChildLrc, leftBottomChildLrc, rightTopChildLrc, rightBottmChildLrc);
                        let tileSwitcher = new TileSwitcher(self.baseTileMap, oldTile, newTileNumList, tileRange);
                        let isSwitch = tileSwitcher.switch(tileList); //判断newTileNumList中的瓦片是否在当前地图层级，并且是否在当前地图加载范围内
                        if (!isSwitch) {
                            removeArray.push(oldTile);
                        } else {
                            self.tileTaskMap.set(parentLrcStr, tileSwitcher);
                            switcherList.push(tileSwitcher);

                            self.switcherLru.push(tileSwitcher);
                        }

                        task.complete();
                    },
                }
                this.taskManger.add(task);
            });
        }

        this.taskManger.run();

        for (let i = 0; i < removeCount; i++) {
            let firstSwitcher = this.switcherLru.shift();
            firstSwitcher.cancle();
        }

        let switchEvent = new SwitchEvent(switcherList, removeArray);
        for (let i = 0; i < switcherList.length; i++) {
            let tileSwitcher = switcherList[i];
            tileSwitcher.setSwitchEvent(switchEvent);
        }
        return tileList;
    }
}

class SwitchEvent {
    private switcherList: Array<TileSwitcher>;
    private removeArray;

    public constructor(switcherList: Array<TileSwitcher>, removeArray) {
        this.switcherList = switcherList;
        this.removeArray = removeArray;
    }

    public event(curSwitcher) {
        let index = this.switcherList.indexOf(curSwitcher);
        this.switcherList.splice(index, 1);


        if (this.switcherList.length == 0) {
            this.removeArray.forEach(element => {
                element.dispose();
            });

            App.getInstance().map.removeTileNoZoom(); //删除不在当前层级的瓦片
        }
        
    }
}
export { TileSwitchController, SwitchEvent }